// 9. 动态内存
/**
 * 1. 栈和堆的概念
 * 2. 什么时候使用动态内存
 *      很多时候，您无法提前预知需要多少内存来存储某个定义变量中的特定信息，所需内存的大小需要在运行时才能确定。
 * 3. new运算符
 *      为给定类型的变量在运行时分配堆内的内存，这会返回所分配的空间地址。
 *      语法: new data_type;
 *      示例:
 *            double* pvalue  = NULL; // 初始化为 null 的指针
 *            pvalue  = new double;   // 为变量请求内存
 *          
 * 4. delete运算符
 *      如果您不再需要动态分配的内存空间，可以使用 delete 运算符，删除之前由 new 运算符分配的内存。
 *      示例：
 *            delete pvalue;        // 释放 pvalue 所指向的内存
 * 
 * 5. #51分配内存失败
 *       如果自由存储区已被用完，可能无法成功分配内存。所以建议检查 new 运算符是否返回 NULL 指针。
 *      double* pvalue  = NULL;
        if( !(pvalue  = new double ))
        {
          cout << "Error: out of memory." <<endl;
          exit(1);
        
        }
 * 6. malloc() 函数与 new运算符比较
 *       new会创建对象，函数运行结束时析构对象
 *       malloc:
 *          语法: void *malloc(size_t _Size)
 *          示例: Test *pt = (Test *)malloc(sizeof(Test));
 * 
 * 7. 数组的动态内存分配
 *    一维数组

    int *array=new int [m];// 动态分配,数组长度为 m
    delete [] array;//释放内存

 * 
 *    二维数据
  
        int **array
        // 假定数组第一维长度为 m， 第二维长度为 n
        // 动态分配空间
        array = new int *[m];
        for( int i=0; i<m; i++ )
        {
            array[i] = new int [n]  ;
        }
        //释放
        for( int i=0; i<m; i++ )
        {
            delete [] array[i];
        }
        delete [] array;

 *    三维数组
 
        int ***array;
        // 假定数组第一维为 m， 第二维为 n， 第三维为h
        // 动态分配空间
        array = new int **[m];
        for( int i=0; i<m; i++ )
        {
            array[i] = new int *[n];
            for( int j=0; j<n; j++ )
            {
                array[i][j] = new int [h];
            }
        }
        //释放
        for( int i=0; i<m; i++ )
        {
            for( int j=0; j<n; j++ )
            {
                delete[] array[i][j];
            }
            delete[] array[i];
        }
        delete[] array;

    总结：多维数组从外层向内层申请空间，从内层向外层释放空间。
    注意：调用多维数组元素,直接使用arr[i][j][k],不像由数组强型转化的指针必需要指针运算才能拿到。
  
  8. #81对象的动态内存分配
     示例
        Test *pt = new Test;
        Test *pt = new Test(1);
        delete pt;

        Test *arr = new Test[10];
        Test *arr = new Test[10]{(1),(2)};

        delete[] arr;

      注意：
        1.对象动态分配内存时，会调用构造函数，可以带括号传参，对象数组后面跟 参数数组，可以指定对应对象元素调用构造函数时传递的参数.
        2. delete会调用析构函数
        3. new [] 一定要和delete[] 配套使用，new和delete最好配套使用。
    
*/
#include <iostream>

#define __mark 81

#if 51 == __mark

/**
 * #51 分配内存失败
*/
int main(void)
{
  int *a = NULL;
  int num = 0;
  for (int i = 0; i < 1000000; i++)
  {
    if (!(a = new int))
    {
      std::cerr << "Error: out of memory!" << std::endl;
      exit(-1);
    }
    num++;
  }
  std::cout << "num: " << num << std::endl;
  printf("-----------end-------------\n");
  return 0;
}
#elif 81 == __mark
/**
 * #81 对象的动态内存分配
*/
class Test
{
public:
  int a;
  Test() : a(0) { std::cout << "调用构造函数" << std::endl; }
  Test(int _a) : a(_a) { std::cout << "调用有参构造函数" << std::endl; }
  ~Test() { std::cout << "调用析构函数" << std::endl; }
};
int main(void)
{
  Test *pt = new Test;
  // Test *pt = new Test(1);
  delete pt;
  // Test t1;// 栈

  // 对象数组
  Test *arr = new Test[10]{(1),(2)};
  delete[] arr;

  printf("-----------end-------------\n");
  return 0;
}
#endif